import { Group } from "three/src/objects/Group";
import { open } from "shapefile";
import { Shape, ExtrudeGeometry, MeshBasicMaterial, Mesh, CanvasTexture, LinearFilter, ClampToEdgeWrapping, PlaneGeometry, Color, Vector2, Vector3, Object3D } from "three";
import { App, GeoUtils, HtmlMarker, Point } from "../../Engine";
import { mergeGeometries } from "three/examples/jsm/utils/BufferGeometryUtils";
import Const from "../../application/constants/Const";
import Helper from "../../utils/Helper";
import TransCoder from "../../utils/TransCoder";
import Config from "../../application/constants/Config";
import TilePort from "./TilePort";
import PoiCollisionManager from "../../map/utils/PoiCollisionManager";
import MeshUtil from "../../renderExtension/utils/MeshUtil";
import Events from "../../application/constants/Events";
import { CustomMeshPhongMaterial } from "../../renderExtension/Material/CustomMaterial";
import ShaderConst from "../../renderExtension/Material/ShaderConst";
import AdjustHeight from "./utils/AdjustHeight";

/**
 * shp对象
 */
class ShapeObject extends Group implements TilePort {
    /**
     * shp文件url
     */
    public urls: string[];
    private srcUrl;
    private srcUse; //POI图标是否加载
    private loaded: Function;
    private geometries = [];
    private lines = [];
    private polygons = [];
    private centerPoint;
    public options;
    private requestMap: Map<string, XMLHttpRequest> = new Map<string, XMLHttpRequest>(); jsono: string;
    private clapData: { isOpenClap: boolean, clapPointArray: [], clapPointCount: number, renderSide: number };
    private hasHtmlMarker;
    private maxWidth: number;
    private buildingType: string = 'buildingType';
    private buildingMaterial;
    public falldownSurface: Object3D;

    /**
     * 构造函数
     * @param options 配置项
     * @param options.url：shp文件地址,如果是数组类型则加载多个shp
     * @param options.lineWidth：矢量的线宽度
     * @param options.lineColor: 线颜色
     * @param options.heightField: shp中代表建筑高度的字段 
     * @param options.polygonFillColor:矢量填充颜色
     * @param options.buildingColor:建筑颜色
     * @param options.textSize: POI文字大小
     * @param options.baseImageSize: POI图片大小
     * @param options.showText: POI是否显示文字
     * @param options.backGroundColor: POI文字背景颜色
     * @param options.textColor: POI文字颜色
     * @param options.merge: 是否合并几何体，默认合并，合并几何体会大幅提升性能，但是会导致无法单体化选中
     * @param options.loaded: 成功加载shp后的回调函数
     * @example        
     *  let shapeObject = new GE.ShapeObject({
            url: [
                '/examples/resources/shp/yuhang_all/buildings.shp',
                '/examples/resources/shp/yuhang_all/places.shp',
                '/examples/resources/shp/yuhang_all/points.shp',
                '/examples/resources/shp/yuhang_all/railways.shp',
                '/examples/resources/shp/yuhang_all/roads.shp',
                '/examples/resources/shp/yuhang_all/waterways.shp',
                '/examples/resources/shp/yuhang_all/natural.shp',
                '/examples/resources/shp/yuhang_all/landuse.shp',
            ],
            // url: '/examples/resources/shp/yuhang_all/natural.shp',
            heightField: 'H', //shp中代表建筑高度的字段
            lineWidth: 5, //矢量的线宽度
            merge: true //此参数设置为true后会大幅提升性能但是无法单体化
        });
        app.add(shapeObject);
     */
    constructor(options: {
        url: Array<string> | string, srcUrl: string, srcUse: boolean, lineWidth?: string, lineColor?: string, heightField?: string,
        polygonFillColor?: string, buildingColor?: string, textSize?: number, baseImageSize?: number, showText?: boolean,
        backGroundColor?: string, textColor?: string, merge?: boolean, loaded?: Function
    }) {
        super();
        this.urls = Array.isArray(options.url) ? options.url : [options.url];    
        this.srcUrl = options.srcUrl;
        this.srcUse = options.srcUse;   
        this.loaded = options.loaded;
        this.maxWidth = window.outerWidth / 10;

        this.options = JSON.parse(JSON.stringify(Object.assign(Config.ShapeConfig, options)));
        this.load();
    }

    /**
     * 加载对象，无需主动调用
     */
    public load() {
        let self = this;        

        for (let i = 0; i < this.urls.length; i++) {
            let xhr = new XMLHttpRequest();

            // 设置请求方式和URL
            let url = this.urls[i];
            xhr.open('GET', url, true);
            self.requestMap.set(url, xhr);
            // 设置响应类型为 arraybuffer
            xhr.responseType = 'arraybuffer';
            // 注册事件处理程序，处理加载完成的数据
            xhr.onload = function () {
                if (xhr.status === 200) {

                    // 解析 Shapefile 数据
                    self.loadShape(xhr.response, self.urls[i].replace('.shp', '.dbf'));
                }
                self.requestMap.delete(url);
            };

            // 注册事件处理程序，处理错误
            xhr.onerror = function () {
                if (self.loaded) {
                    self.loaded(self);
                }

                if(self.requestMap){
                    self.requestMap.delete(url);
                }
            };

            // 发送请求
            xhr.send();
            // self.loadShape(this.urls[i]);
        }
    }

    private loadShape(data, dbf) {
        let self = this;
        try {
            open(data, dbf)
                .then(
                    source => source.read()
                        .then(function log(result) {
                            // console.log(result.value.geometry.type)
                            if (result.done) {
                                if (self.options.merge) {
                                    self.merge();
                                }
                                if (self.loaded) {
                                    self.loaded(self);
                                }
                                self.clap();
                                
                                return;
                            }
                            self.parseShapeData(result.value);
                            App.getInstance().fireEvent(Events.AddTile); //添加了新的瓦片，对外广播通知
                            return source.read().then(log);
                        })

                )
                .catch((error) => {
                });

        } catch (error) {
            if (self.loaded) {
                self.loaded(self);
            }
        }
    }

    private parseShapeData(data) {
        let self = this;
        switch (data.geometry.type) {
            case 'MultiPolygon': {
                data.geometry.coordinates.forEach(multiPolygonArray => {
                    //有高度字段则使用shapeExtrudeGeometry做几何体拉伸
                    if (data.properties[self.options.heightField]) {
                        multiPolygonArray.forEach(pointArray => {
                            if (!self.options.merge)
                                self.addMesh(pointArray, data.properties);
                            else
                                self.buildMergeMesh(pointArray, data.properties);
                        });
                    }
                    else {
                        multiPolygonArray.forEach(pointArray => {
                            self.addPolygon(pointArray, data.properties);
                        });
                    }
                });
                break;
            }
            case 'Polygon': {
                data.geometry.coordinates.forEach(pointArray => {
                    //有高度字段则使用shapeExtrudeGeometry做几何体拉伸
                    if (data.properties[self.options.heightField]) {
                        if (!self.options.merge)
                            self.addMesh(pointArray, data.properties);
                        else
                            self.buildMergeMesh(pointArray, data.properties);
                    }
                    //无高度字段则绘制到canvas上做平面贴图
                    else {
                        self.addPolygon(pointArray, data.properties);
                    }
                });
                break;
            }
            case 'Point': {
                this.addPoi(data);
                break;
            }
            case 'LineString': {
                this.addLineString(data, data.properties);
                break;
            }
            default:
                return;
        }
    }

    private decodeStr(str){
          //shapefile工具库默认用windows-1252编码，所以不支持中文
          var enc = new TransCoder("windows-1252");
          //将字符串转为arraybuffer
           var buffer = enc.transcode(str);
          //使用utf-8编码对arraybuffer解码，得到中文
          var decoder = new TextDecoder(this.options.textEncode);
          //   var decoder = new TextDecoder("gbk");
          var value = decoder.decode(buffer);
          return value;
    }

    /**
     * 添加多边形
     * @param data 
     */
    private addPolygon(data, properties) {
        this.polygons.push({
            data: data,
            properties: properties
        });
    }
    /**
     * 暂时将数据记录在内存中
     * @param data 
    */
    private addLineString(data, properties) {
        this.lines.push({
            data: data,
            properties: properties
        });
    }

    /**
     * 根据数据将POI添加至场景中
     * @param data 
     */
    private addPoi(data) {
        var name = this.decodeStr(data.properties.name);

        // let name = this.convertWindows1252ToUTF8(data.properties.name);
        let epsgType = Helper.isLatLng(data.geometry.coordinates[0], data.geometry.coordinates[1]) ? Const.EPSGType.EPSG84 : Const.EPSGType.EPSGWeb;
        // let poi = new Poi({
        //     url: 'http://192.168.2.100:8701/dev/examples/resources/images/tower.png', //模型图片路径
        //     position: new Point(data.geometry.coordinates[0], data.geometry.coordinates[1], 30, epsgType), //POI位置，不传就是0,0,0原点
        //     name: name, //显示的文字名称
        //     size: this.options.textSize, //文字大小
        //     isBold: true, //是否加粗
        //     baseImageSize: this.options.baseImageSize, //图片大小（长宽一致，都是这个值）
        //     showText: this.options.showText,//是否显示文字
        //     backGroundStyle: this.options.backGroundColor, //字体背景色
        //     textStyle: this.options.textColor,//字体颜色
        //     textfont: 'sans-serif'//字体格式 字体的支持情况跟操作系统和浏览器环境有关，sans-serif是默认字体都支持，其余字体不保证正常显示
        // });
        // poi.material.transparent = true;
        // poi.material.depthTest = false;
        // poi.renderOrder = Const.RenderOrder.ShapePoi;
        // this.add(poi);

        let div = document.createElement('div');
        div.className = 'label';
        div.textContent = 'HTMLMarker';
        div.style.backgroundColor = 'transparent';
        div.style.color = '#' + new Color(this.options.textColor).getHexString();
        div.style.maxWidth = this.maxWidth + 'px';
        div.style.wordBreak = 'break-word';
        div.innerText = name;

        //
        if(this.srcUse)
        {
            var img = document.createElement("img");
            if(data.properties.type != undefined)
            {
                img.src = this.srcUrl + data.properties.type +'.png';
                //img.src = 'http://192.168.2.44:9000/examples/resources/shp/images/'+ data.properties.type +'.png';
                //img.src = 'http://192.168.2.44:9000/examples/resources/shp/images/test.jpg';
            }
            img.style.width = "32px";
            img.style.height = "32px";
            img.style.top = "0px";
            img.style.left = "0px";
            div.appendChild(img);
        }        

        let isCollisionCheck = true;
        if(!this.options.lrc){
            isCollisionCheck = false;
        }
        let label = new HtmlMarker(div, {position: null, isCollisionCheck: isCollisionCheck});
        //设置组件在三维场景中的位置
        let position = new Point(data.geometry.coordinates[0], data.geometry.coordinates[1], 0, epsgType).toEPSGWeb(); //POI位置，不传就是0,0,0原点
        label.position.set(position.x, position.y, 0);
        //设置对其方式，0,0为中心对齐
        label.center.set(0, 0);
        //将组件添加至场景中
        this.add(label);
        // if(this.options.lrc){
        //     console.log(this.options.lrc);
        //     PoiCollisionManager.addPoiTile(this.options.lrc, label);
        // }
        let tileJson = this.options.lrc;
        label.openCollisionCheck(tileJson)
        this.hasHtmlMarker = true;
    }


    /**
     * 根据参数将几何体添加至场景中
     * @param pointArray 
     * @param properties 
     */
    private addMesh(pointArray, properties) {
        let epsgType = Helper.isLatLng(pointArray[0][0], pointArray[0][1]) ? Const.EPSGType.EPSG84 : Const.EPSGType.EPSGWeb;
        let centerPoint = new Point(pointArray[0][0], pointArray[0][1], 0, epsgType).toEPSGWeb(); //pointArray[0];
        let shape = new Shape();
        pointArray.forEach((point, i) => {
            let currentPoint = new Point(point[0], point[1], 0, epsgType).toEPSGWeb();
            currentPoint = currentPoint.clone().sub(centerPoint);
            i == 0 ? shape.moveTo(currentPoint.x, currentPoint.y) : shape.lineTo(currentPoint.x, currentPoint.y);
        });

        let extrudeSettings = {
            depth: properties[this.options.heightField],
        };

        let geometry = new ExtrudeGeometry(shape, extrudeSettings);
        let macrosList:Array<string> = new Array<string>();
        macrosList.push(ShaderConst.macrosConfig.floorRangeMacros);

        if(!this.buildingMaterial){
            let materialParam = {
                coreParameters: {
                    transparent: true,
                    color: this.options.buildingColor,
                    side: this.options.renderSide,
                },
                macrosList: macrosList,
                identity: 'shapeMeshMaterial'
            };
            this.buildingMaterial = new CustomMeshPhongMaterial(materialParam); //new CustomMeshBasicMaterial(materialParam);
            this.setBuildingFloorRange(this.buildingMaterial);
        }
        
        let mesh = new Mesh(geometry, this.buildingMaterial);
        mesh[this.buildingType] = true;
        //@ts-ignore
        mesh.shpProperty = properties;
        //mesh.position.set(centerPoint.x - this.position.x, centerPoint.y - this.position.y, centerPoint.z - this.position.z);
        mesh.position.set(centerPoint.x, centerPoint.y, centerPoint.z);
        mesh.renderOrder = Const.RenderOrder.ShapeBuildings;
        this.add(mesh);

        if (this.falldownSurface) {
            let adjustHeightData = {mesh: mesh, falldownSurface: this.falldownSurface};
            let adjustHeightUtil = new AdjustHeight(adjustHeightData);
            adjustHeightUtil.startAdjust();
        }
    }

    /**
     * 构建要合并的几何体，只是暂时记录下信息
     * @param pointArray 
     * @param properties 
     */
    private buildMergeMesh(pointArray, properties) {
        let epsgType = Helper.isLatLng(pointArray[0][0], pointArray[0][1]) ? Const.EPSGType.EPSG84 : Const.EPSGType.EPSGWeb;
        if (!this.centerPoint)
            this.centerPoint = new Point(pointArray[0][0], pointArray[0][1], 0, epsgType).toEPSGWeb();

        let shape = new Shape();
        let self = this;
        pointArray.forEach((point, i) => {
            let currentPoint = new Point(point[0], point[1], 0, epsgType).toEPSGWeb();
            currentPoint = currentPoint.clone().sub(self.centerPoint);
            i == 0 ? shape.moveTo(currentPoint.x, currentPoint.y) : shape.lineTo(currentPoint.x, currentPoint.y);
        });

        let extrudeSettings = {
            depth: properties[this.options.heightField],
        };
        let geometry = new ExtrudeGeometry(shape, extrudeSettings);
        this.geometries.push(geometry);
    }
    private merge() {
        this.mergeMesh();
        this.mergeLines();
        this.mergePolygons();
    }
    
    private mergePolygons() {
        if (!this.polygons || this.polygons.length == 0){
            return;
        }
            
        let width = 100;
        let height = 100;

        let polygons = [];
        //遍历数据，全部转mecator数据，并计算出最大最小xy值
        let minx = Number.MAX_VALUE, miny = Number.MAX_VALUE, maxx = Number.MIN_VALUE, maxy = Number.MIN_VALUE;
        for (let j = 0; j < this.polygons.length; j++) {
            let coordinates = this.polygons[j].data;
            let points = [];
            for (let i = 0; i < coordinates.length; i++) {
                let epsgType = Helper.isLatLng(coordinates[i][0], coordinates[i][1]) ? Const.EPSGType.EPSG84 : Const.EPSGType.EPSGWeb;
                let point = new Point(coordinates[i][0], coordinates[i][1], coordinates[i][2] ? coordinates[i][2] : 0, epsgType).toEPSGWeb();
                points.push(point);

                minx = minx < point.x ? minx : point.x;
                miny = miny < point.y ? miny : point.y;
                maxx = maxx > point.x ? maxx : point.x;
                maxy = maxy > point.y ? maxy : point.y;
            }
            polygons.push({
                points: points,
                properties: this.polygons[j].propertiesr
            });
        }

        //计算出矢量数据的长宽 添加lineWidth避免矢量数据边缘被裁剪掉的显示异常
        let lineWidth = this.options.showBorder ? this.options.polygonBorderWidth : 0;
        width = Math.abs(maxx - minx) + lineWidth * 2;
        height = Math.abs(maxy - miny) + lineWidth * 2;

        //初始化Canvas对象
        const ctx = document.createElement('canvas').getContext('2d');
        //canvas缩放系数
        let n = 1;
        let maxRange = 10000;
        if (this.options.maxPixel && width * height > this.options.maxPixel) {
            n = Math.sqrt(this.options.maxPixel / width * height);
        }
        else if(width > maxRange || height > maxRange){
            n = 2.5; //优化canvas的长宽太大，无法渲染出来的问题。目前只是一种暂时的方案，该问题要解决最好还是要对shape数据进行切割
        }
        ctx.canvas.width = (n == 1) ? width : width / n;
        ctx.canvas.height = (n == 1) ? height : height / n;


        //取数据中心点为平面对象中心，后续canvas的线绘制都基于中心位置做偏移
        let center = new Point(minx + width / 2, miny + height / 2, 0, Const.EPSGType.EPSGWeb);
        let startX = polygons[0].points[0].x - center.x + width / 2 + lineWidth;
        //canvas左上角是0，0点，shape数据左下角是0,0点，所以y轴要反过来
        let startY = center.y - polygons[0].points[0].y + height / 2 - lineWidth;

        //在canvas上画线
        if (this.options.polygonBorderColor && this.options.showBorder) {
            ctx.strokeStyle = this.options.polygonBorderColor;
        }
        else {
            ctx.strokeStyle = (polygons[0].properties && this.options.polygonConfig[polygons[0].properties['type']]) ? this.options.polygonConfig[polygons[0].properties['type']].color : this.options.polygonFillColor;
        }
        ctx.fillStyle = (polygons[0].properties && this.options.polygonConfig[polygons[0].properties['type']]) ? this.options.polygonConfig[polygons[0].properties['type']].width : this.options.polygonFillColor;
        // ctx.strokeStyle = this.options.polygonFillColor;
        // ctx.fillStyle = this.options.polygonFillColor;
        ctx.lineWidth = lineWidth;

        ctx.lineCap = 'round';
        for (let j = 0; j < polygons.length; j++) {
            let points = polygons[j].points;
            if (this.options.polygonBorderColor && this.options.showBorder) {
                ctx.strokeStyle = this.options.polygonBorderColor;
            }
            else {
                ctx.strokeStyle = (polygons[0].properties && this.options.polygonConfig[polygons[j].properties['type']]) ? this.options.polygonConfig[polygons[j].properties['type']].color : this.options.polygonFillColor;
            }
            ctx.fillStyle = (polygons[0].properties && this.options.polygonConfig[polygons[j].properties['type']]) ? this.options.polygonConfig[polygons[j].properties['type']].color : this.options.polygonFillColor;

            for (let i = 0; i < points.length; i++) {
                let offsetX = (points[i].x - center.x + width / 2 + lineWidth) / n;
                let offsetY = (center.y - points[i].y + height / 2 - lineWidth) / n;

                if (i == 0) {
                    ctx.moveTo(offsetX, offsetY);
                    ctx.beginPath();
                }
                else {
                    ctx.lineTo(offsetX, offsetY);
                }
            }
            ctx.closePath();
            ctx.fill();
            ctx.stroke();
        }

        // ctx.stroke();

        //使用canvasTexture将绘制好的图像放到材质上
        const texture = new CanvasTexture(ctx.canvas);
        // texture.minFilter = LinearMipMapLinearFilter;
        // texture.magFilter = NearestMipmapNearestFilter;
        // texture.mapping = 304;
        // texture.wrapS = ClampToEdgeWrapping;
        // texture.wrapT = ClampToEdgeWrapping;
        let material = new MeshBasicMaterial({
            map: texture,
            transparent: true,
        });
        material.depthTest = false;
        let geometry = new PlaneGeometry(width, height, 10, 10);
        let mesh = new Mesh(geometry, material);
        mesh.renderOrder = Const.RenderOrder.ShapePolygon;;
        //平面对象的位置就是数据的中心位置
        mesh.position.set(center.x, center.y, 0.1);
        this.add(mesh);


        this.polygons = [];
    }


    /**
     * 根据数据构造矢量对象，采用Canvas贴图的方式
     * @returns 
     */
    private mergeLines() {
        if (!this.lines || this.lines.length == 0)
            return;
        let width = 100;
        let height = 100;

        let lines = [];
        //遍历数据，全部转mecator数据，并计算出最大最小xy值
        let minx = Number.MAX_VALUE, miny = Number.MAX_VALUE, maxx = Number.MIN_VALUE, maxy = Number.MIN_VALUE;
        for (let j = 0; j < this.lines.length; j++) {
            let data = this.lines[j].data;
            let points = [];
            for (let i = 0; i < data.geometry.coordinates.length; i++) {
                let epsgType = Helper.isLatLng(data.geometry.coordinates[i][0], data.geometry.coordinates[i][1]) ? Const.EPSGType.EPSG84 : Const.EPSGType.EPSGWeb;
                let point = new Point(data.geometry.coordinates[i][0], data.geometry.coordinates[i][1], data.geometry.coordinates[i][2] ? data.geometry.coordinates[i][2] : 0, epsgType).toEPSGWeb();
                points.push(point);

                minx = minx < point.x ? minx : point.x;
                miny = miny < point.y ? miny : point.y;
                maxx = maxx > point.x ? maxx : point.x;
                maxy = maxy > point.y ? maxy : point.y;
            }
            lines.push({
                points: points,
                properties: this.lines[j].properties
            });
        }

        //计算出矢量数据的长宽 添加lineWidth避免矢量数据边缘被裁剪掉的显示异常
        let lineWidth = this.options.lineWidth;
        width = Math.abs(maxx - minx) + lineWidth * 2;
        height = Math.abs(maxy - miny) + lineWidth * 2;

        //初始化Canvas对象
        const ctx = document.createElement('canvas').getContext('2d');
       //canvas缩放系数
        let n = 1;
        let maxRange = 10000;
        if (this.options.maxPixel && width * height > this.options.maxPixel) {
            n = Math.sqrt(this.options.maxPixel / width * height);
        }
        else if(width > maxRange || height > maxRange){
            n = 2.5; //优化canvas的长宽太大，无法渲染出来的问题。目前只是一种暂时的方案，该问题要解决最好还是要对shape数据进行切割
        }
        ctx.canvas.width = (n == 1) ? width : width / n;
        ctx.canvas.height = (n == 1) ? height : height / n;

        //取数据中心点为平面对象中心，后续canvas的线绘制都基于中心位置做偏移
        let center = new Point(minx + width / 2, miny + height / 2, 0, Const.EPSGType.EPSGWeb);
        let startX = lines[0].points[0].x - center.x + width / 2 + lineWidth;
        //canvas左上角是0，0点，shape数据左下角是0,0点，所以y轴要反过来
        let startY = center.y - lines[0].points[0].y + height / 2 - lineWidth;
        
        //在canvas上画线
        ctx.strokeStyle = (lines[0].properties && this.options.lineConfig[lines[0].properties['type']]) ? this.options.lineConfig[lines[0].properties['type']].color : this.options.lineColor;
        ctx.lineWidth = (lines[0].properties && this.options.lineConfig[lines[0].properties['type']]) ? this.options.lineConfig[lines[0].properties['type']].width : this.options.lineWidth;
        ctx.lineCap = 'round';

        for (let j = 0; j < lines.length; j++) {
            let points = lines[j].points;
            ctx.strokeStyle = (lines[0].properties && this.options.lineConfig[lines[j].properties['type']]) ? this.options.lineConfig[lines[j].properties['type']].color : this.options.lineColor;
            ctx.lineWidth = (lines[0].properties && this.options.lineConfig[lines[j].properties['type']]) ? this.options.lineConfig[lines[j].properties['type']].width : this.options.lineWidth;
            ctx.lineCap = 'round';
            for (let i = 0; i < points.length; i++) {
                let offsetX = (points[i].x - center.x + width / 2 + lineWidth) / n;
                let offsetY = (center.y - points[i].y + height / 2 - lineWidth) / n;
                //第一个点调用moveTo
                if (i == 0)
                    ctx.moveTo(offsetX, offsetY);
                else
                    ctx.lineTo(offsetX, offsetY);
            }
        }
        ctx.stroke();
        //使用canvasTexture将绘制好的图像放到材质上
        const texture = new CanvasTexture(ctx.canvas);
        // texture.minFilter = LinearFilter;
        texture.wrapS = ClampToEdgeWrapping;
        texture.wrapT = ClampToEdgeWrapping;
        let material = new MeshBasicMaterial({
            map: texture,
            transparent: true,
        });
        material.depthTest = false;
        let geometry = new PlaneGeometry(width, height, 10, 10);
        let mesh = new Mesh(geometry, material);
        //平面对象的位置就是数据的中心位置
        mesh.position.set(center.x, center.y, 0.2);
        mesh.renderOrder = Const.RenderOrder.ShapeLine;
        this.add(mesh);
        this.lines = [];
    }
    /**
     * 合并几何体并添加至场景中
     */
    private mergeMesh() {
        if (!this.geometries || this.geometries.length == 0)
            return;
        let mergedGeometry = mergeGeometries(this.geometries);
        // let customData = this.options.customData;

        let macrosList:Array<string> = new Array<string>();
        macrosList.push(ShaderConst.macrosConfig.floorRangeMacros);

        if(!this.buildingMaterial){
            let materialParam = {
                coreParameters: {
                    transparent: true,
                    color: this.options.buildingColor,
                    side: this.options.renderSide,
                },
                macrosList: macrosList,
                identity: 'mergeShapeMeshMaterial'
            };
    
            this.buildingMaterial = new CustomMeshPhongMaterial(materialParam);
            this.setBuildingFloorRange(this.buildingMaterial);
        }
        
        let mergeMesh = new Mesh(mergedGeometry, this.buildingMaterial);
        mergeMesh[this.buildingType] = true;
        mergeMesh.position.set(this.centerPoint.x, this.centerPoint.y, this.centerPoint.z);
        this.add(mergeMesh);
        mergeMesh.renderOrder = Const.RenderOrder.ShapeBuildings;
        this.geometries = [];
    }

    private setBuildingFloorRange(material, floorDivisionArray?) {
        if(this.options.floorDivisionArray && this.options.floorDivisionArray.length > 0){ //有划分楼层的数据
            let floorRangeArray:Array<Vector2> = new Array<Vector2>();
            let floorColorArray:Array<Vector3> = new Array<Vector3>();

            if(!floorDivisionArray){
                floorDivisionArray = this.options.floorDivisionArray;
            }

            //如果floorDivisionArray中的数据项少于配置项中的数量，则用第一个数据项填充。这样做是为了避免在ShaderConst.getFragmentFloorDivision方法中的shader出错
            if(floorDivisionArray.length < App.getInstance().options.ShapeConfig.floorDivisionCount){
                let leftCount = App.getInstance().options.ShapeConfig.floorDivisionCount - floorDivisionArray.length;
                for(let i = 0; i < leftCount; i++){
                    floorDivisionArray.push(floorDivisionArray[0]);
                }
            }

            floorDivisionArray.forEach(element => {
                let floorRange = element.floorRange;
                let startLevel = floorRange.startLevel;
                let endLevel = floorRange.endLevel;
                floorRangeArray.push(new Vector2(startLevel, endLevel));

                let floorColor = new Color(element.floorColor);
                floorColorArray.push(new Vector3(floorColor.r, floorColor.g, floorColor.b));

            });

            if(floorDivisionArray.length > 0){
                if (material.length > 1) {
                    material.forEach(element => {
                        element.material['setFloorDivisionData']({floorRangeArray: floorRangeArray, floorColorArray: floorColorArray, isOpenFloorDivision: true});
                    });
                } else {
                    material['setFloorDivisionData']({floorRangeArray: floorRangeArray, floorColorArray: floorColorArray, isOpenFloorDivision: true});
                }
            }
           
           
        }
    }

    public setAllBuildingFloorRange(floorDivisionArray) {
        this.options.floorDivisionArray = floorDivisionArray;
        
        let self = this;
        Helper.traverseObject(this, function(obj){
            if(obj.type == 'Mesh' && obj[self.buildingType] == true){
                self.setBuildingFloorRange(obj.material, floorDivisionArray);
            }
        });
    }

    public dispose() {
        MeshUtil.dispose(this);
        if(this.options.lrc){
            PoiCollisionManager.removePoiTile(this.options.lrc); //删除poi碰撞管理器中的数据
        }

        this.cancleNetTask();
    }

    public cancleNetTask(){
        if (this.requestMap) {
            this.requestMap.forEach(xhr => {
                xhr.abort();
            });
            this.requestMap.clear();
        }
        this.requestMap = null;
    }

    public setCut(clapData: { isOpenClap: boolean, clapPointArray: [], clapPointCount: number, renderSide: number }) {
        this.clapData = clapData;
    }

    private clap() {
        let self = this;
        if (!this.clapData) {
            return;
        }

        Helper.traverseObject(this, function (obj) {
            if (obj.type == 'Mesh') {
                if (obj.material.length > 1) {
                    obj.material.forEach(element => {
                        element.material.setCut(self.clapData);
                    });
                } else {
                    obj.material.setCut(self.clapData);
                }
            }
            return true;
        });
    }

    
    public updateVisibility(){
        this.visible = false;
    }

    public restoreVisibility(){
        this.visible = true;
    }
}
export { ShapeObject }